/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package exclusionmutua;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.text.MessageFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.SecretKey;
import seguridad.ManagerSeguridad;
import utilidades.Manejador;
import vista.Inicio;

/**
 *
 * @author Eduardo
 */
public class ManejadorConexionEM extends Manejador {

    public ManejadorConexionEM() {
        super();
    }

    @Override
    public void enviar(Socket socket, String pathname) {
        try { byte[] llaveSecretaCifrada = super.getLlaveSecreta();
            long start = System.currentTimeMillis();
            // get the socket output stream
            OutputStream out = socket.getOutputStream();
            //Para escribir el tamaño del archivo
            DataOutput dos = new DataOutputStream(out);

            // 0.0 Enviar el tamaño de la llave secreta
            dos.writeInt(llaveSecretaCifrada.length);
            //0.1 Enviar llave secreta encriptada con llave pública del servidor
            dos.write(llaveSecretaCifrada, 0, llaveSecretaCifrada.length);

            //Cargando la referencia al archivo
            //File miArchivo = new File(pathname);

            ManagerSeguridad.cifrarArchivoConLlaveSecretaLocal(seguridad.ConvertirArchivo.quitarExtension(pathname));


            File miArchivo = new File(pathname);
            System.out.println("EXCLUSION MUTUA: Se encontro el archivo, nombre: " + miArchivo.getName());
            //Creando el buffer

            byte[] out_buf = new byte[(int) miArchivo.length()];

            //1. Enviar el tamaño del archivo
            dos.writeInt(out_buf.length);
            System.out.println("EXCLUSION MUTUA: Enviado tamaño archivo: " + out_buf.length);
            //2. Enviar el nombre del archivo
            dos.writeUTF(miArchivo.getName());

            ///toca esperar un tiempito


            //Cargando el inputstream de archivos
            FileInputStream fis = new FileInputStream(miArchivo);
            //Cargando el buffer
            BufferedInputStream bis = new BufferedInputStream(fis);
            //leyendo desde el buffer
            bis.read(out_buf, 0, out_buf.length);

            //Como lo estoy devolviendo no esta cifrado por lo tanto esta linea no es necesario.
            //out_buf = ManagerSeguridad.decifrarArchivoRemotoConLLaveSecretaLocal(out_buf);
        // ya se cifro    out_buf = ManagerSeguridad.cifrarArchivoConLlaveSecretaLocal(out_buf);

            //3. Enviar el archivo
            out.write(out_buf, 0, out_buf.length);
            //cerrando las conexiones
            out.flush();
            out.close();
            socket.close();
            System.out.println("Socket connection closed");
            //Calculando el tiempo de duración de la transmisión
            long finish = System.currentTimeMillis();
            long elapsed = finish - start;

            System.out.println(MessageFormat.format(
                    "EOT. Processed {0} bytes in {1} ms. Throughput = {2} KB/sec.",
                    out_buf.length, elapsed, (1000 / elapsed) * 1000 / 1024));
            synchronized (lock) {
                lock.notifyAll();
            }
            if(miArchivo.delete())
                System.out.println("Archivo borrado con exito.");

        } catch (IOException io) {
            io.printStackTrace();
        }
    }

    @Override
    public void recibir(Socket socket, String pathname, String idArchivo) {

        try {
            long start = System.currentTimeMillis(); //hora del sistema
            InputStream in = socket.getInputStream();
            //Flujo de datos de java
            DataInput dis = new DataInputStream(in);

              //0.0 Recibir el tamaño del la clave cifrada
            int sizeClave = dis.readInt();
            //0.1 Recibo la llave secreta del cliente encriptada con mi llave pública
             byte[] llaveSecretaEncriptadaRemota = new byte[sizeClave];

             dis.readFully(llaveSecretaEncriptadaRemota);

            //1. Recibir el tamaño del archivo
            int size = dis.readInt();
            System.out.println("EXCLUSION MUTUA: Recibiendo cant. de bytes a descargar: " + size);
            //2. Recibir el nombre del archivo
            String nombre = dis.readUTF();
            //Creando el buffer
            byte[] buf = new byte[size];
            //3. Recibir el archivo
            dis.readFully(buf);
            // se descifra la llave secreta remota con la llave privada local
            SecretKey llaveSecretaRemota = ManagerSeguridad.decifrarConllavePrivadaLaLlaveSecretaRemota(llaveSecretaEncriptadaRemota);
            // se descifra los bytes del arcvhio con la llave secreta remota
            buf = ManagerSeguridad.descifrarArchivoRemotoConLlaveSecretaRemota(llaveSecretaRemota,buf);

            nombre = seguridad.ConvertirArchivo.quitarExtension(nombre);
            System.out.println("EXCLUSION MUTUA: Archivo descargado, nombre: " + nombre);
            //Creando el outputstream

            FileOutputStream fos = new FileOutputStream(pathname + nombre);
            //creando el buffer de salida a disco
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            //escribiendo en disco
            bos.write(buf, 0, buf.length);
            //cerrando conexiones
            bos.flush();
            bos.close();
            in.close();
            socket.close();
            System.out.println("Connection closed");

            long finish = System.currentTimeMillis();
            long elapsed = finish - start;

            System.out.println(MessageFormat.format(
                    "EOT. Processed {0} bytes in {1} ms. Throughput = {2} KB/sec.",
                    size, elapsed, (1000 / elapsed) * 1000 / 1024));
//  se envia la ruta de la EM para que lo agregue a la lista de archivo y luego obtenemos la ruta
         String ruta =  limpiarDevueltos(pathname + nombre);
// ciframos el archivo que se encuentra sin cifrar.
         ManagerSeguridad.cifrarArchivoConLlaveSecretaLocal(ruta+ nombre);


        } catch (EOFException ex) {
            System.err.println("Se acabor el archivo intempestivamente");
            ex.printStackTrace();
        } catch (Exception ie) {
            ie.printStackTrace();
        }
    }


    private String limpiarDevueltos(String pathname) {
        File archivoParaCopiar = new File(pathname);
        String nombreCompleto= archivoParaCopiar.getName();
        String extension = nombreCompleto.substring(nombreCompleto.lastIndexOf(".")+1);
        String ruta = null;
        if (extension.equals("mp3") || extension.equals("wav") || extension.equals("wma")) {
            ruta = Inicio.RUTA_AUDIO;
        } else if (extension.equals("mpg") || extension.equals("avi") || extension.equals("mpeg")) {
            ruta = Inicio.RUTA_VIDEO;
        } else if (extension.equals("pdf") || extension.equals("doc") || extension.equals("docx") || extension.equals("txt")) {
            ruta = Inicio.RUTA_TEXTO;
        }
        try {
            copy(archivoParaCopiar, new File(ruta + nombreCompleto));
            archivoParaCopiar.delete();
            return ruta;

        } catch (IOException ex) {
            System.out.println("Error cuando se intentó copiar el archivo devuelto a la carpeta correspondiente");
            Logger.getLogger(ManejadorConexionEM.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    /**
     * Copia un solo archivo
     * @param src
     * @param dst
     * @throws IOException
     */
    private void copy(File src, File dst) throws IOException {
        InputStream in = new FileInputStream(src);
        OutputStream out = new FileOutputStream(dst);


        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }
        in.close();
        out.close();
    }
}
